package spring.core.extensions;

import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.support.AbstractApplicationContext;

/**
 * Wrapper to always return a reference to the Spring Application Context from
 * within non-Spring enabled beans. Usually this class will be instantiated
 * inside the Spring context and because it is context aware will then provide
 * access to the beans within the context. Spring context must be up and running
 * to make this work. If Spring context is not up and running this class will
 * ramp up a default context.
 */
public abstract class SpringApplicatonContext implements
		ApplicationContextAware {

	/**
	 * The Spring application context that is injected by the Spring
	 * configuration.
	 */
	private ApplicationContext applicationContext;

	/**
	 * This is about the same as context.getBean("beanName"), except it has its
	 * own static handle to the Spring context, so calling this method
	 * statically will give access to the beans by name in the Spring
	 * application context. As in the context.getBean("beanName") call, the
	 * caller must cast to the appropriate target class. If the bean does not
	 * exist, then a Runtime error will be thrown.
	 * 
	 * @param beanName
	 *            the name of the bean to get.
	 * @return an Object reference to the named bean.
	 */
	public Object getBean(String beanName) {
		if (this.applicationContext == null) {
			this.registerDefaultApplicatonContext();
		}
		return this.applicationContext.getBean(beanName);
	}

	/**
	 * Performs additional initialization of the application context. Registers
	 * a hook that will gracefully shut down the Spring application context.
	 * Note: Web-applications already have code in place for shutting down the
	 * Spring context.
	 * 
	 * @return the default application context
	 */
	protected void initializeApplicatonContext() {
		((AbstractApplicationContext) this.applicationContext)
				.registerShutdownHook();
	}

	/**
	 * This method is called if application context has net yet been initialized
	 * and is responsible for initializing the application context.
	 * 
	 * @return the default application context
	 */
	protected abstract void registerDefaultApplicatonContext();

	/**
	 * This method is called from within the ApplicationContext once it is done
	 * starting up, it will stick a reference to itself into this bean.
	 * 
	 * @param applicationContext
	 *            a reference to the ApplicationContext.
	 * @throws BeansException
	 *             the beans exception
	 */
	public void setApplicationContext(ApplicationContext applicationContext)
			throws BeansException {
		this.applicationContext = applicationContext;
		this.initializeApplicatonContext();
	}
}
